cpufreq: Support cpufreq updates on AMD hardware by dom0 kernel.
authorKeir Fraser <keir@xensource.com>
Thu, 20 Sep 2007 13:15:45 +0000 (14:15 +0100)
committerKeir Fraser <keir@xensource.com>
Thu, 20 Sep 2007 13:15:45 +0000 (14:15 +0100)
Signed-off-by: Mark Langsdorf <mark.langsdorf@amd.com>
Signed-off-by: Keir Fraser <keir@xensource.com>
xen/arch/x86/domain.c
xen/arch/x86/platform_hypercall.c
xen/arch/x86/time.c
xen/arch/x86/traps.c
xen/common/schedule.c
xen/include/asm-x86/msr.h
xen/include/asm-x86/time.h
xen/include/public/platform.h
xen/include/xen/sched.h
xen/include/xen/time.h

index 86903a8e65721b9544cbf9feeb4a26f9d2bc729f..2080e70961f0ca966b239a628a670ed84479e57f 100644 (file)
@@ -1378,10 +1378,9 @@ static void continue_hypercall_on_cpu_helper(struct vcpu *v)
     regs->eax = info->func(info->data);
 
     v->arch.schedule_tail = info->saved_schedule_tail;
-    v->cpu_affinity = info->saved_affinity;
+    v->arch.continue_info = NULL;
 
     xfree(info);
-    v->arch.continue_info = NULL;
 
     vcpu_set_affinity(v, &v->cpu_affinity);
     schedule_tail(v);
@@ -1392,6 +1391,7 @@ int continue_hypercall_on_cpu(int cpu, long (*func)(void *data), void *data)
     struct vcpu *v = current;
     struct migrate_info *info;
     cpumask_t mask = cpumask_of_cpu(cpu);
+    int rc;
 
     if ( cpu == smp_processor_id() )
         return func(data);
@@ -1403,12 +1403,19 @@ int continue_hypercall_on_cpu(int cpu, long (*func)(void *data), void *data)
     info->func = func;
     info->data = data;
     info->saved_schedule_tail = v->arch.schedule_tail;
-    v->arch.schedule_tail = continue_hypercall_on_cpu_helper;
-
     info->saved_affinity = v->cpu_affinity;
+
+    v->arch.schedule_tail = continue_hypercall_on_cpu_helper;
     v->arch.continue_info = info;
 
-    vcpu_set_affinity(v, &mask);
+    rc = vcpu_set_affinity(v, &mask);
+    if ( rc )
+    {
+        v->arch.schedule_tail = info->saved_schedule_tail;
+        v->arch.continue_info = NULL;
+        xfree(info);
+        return rc;
+    }
 
     /* Dummy return value will be overwritten by new schedule_tail. */
     BUG_ON(!test_bit(SCHEDULE_SOFTIRQ, &softirq_pending(smp_processor_id())));
index 24568db2246e05a90fa4d360f81cb4585f073da2..86180d1a7329c9b51cd6941bc0745009a4396bea 100644 (file)
@@ -40,6 +40,11 @@ DEFINE_SPINLOCK(xenpf_lock);
 extern spinlock_t xenpf_lock;
 #endif
 
+static long cpu_frequency_change_helper(void *data)
+{
+    return cpu_frequency_change(*(uint64_t *)data);
+}
+
 ret_t do_platform_op(XEN_GUEST_HANDLE(xen_platform_op_t) u_xenpf_op)
 {
     ret_t ret = 0;
@@ -280,6 +285,15 @@ ret_t do_platform_op(XEN_GUEST_HANDLE(xen_platform_op_t) u_xenpf_op)
         ret = acpi_enter_sleep(&op->u.enter_acpi_sleep);
         break;
 
+    case XENPF_change_freq:
+        ret = -EINVAL;
+        if ( op->u.change_freq.flags != 0 )
+            break;
+        ret = continue_hypercall_on_cpu(op->u.change_freq.cpu,
+                                        cpu_frequency_change_helper,
+                                        &op->u.change_freq.freq);
+        break;
+
     default:
         ret = -ENOSYS;
         break;
index 5465cc056e1977d3400a670716ad7d7a60dbe94c..7b23426c6e162565e69ae8655444f72ef0236cd3 100644 (file)
@@ -722,6 +722,27 @@ void update_domain_wallclock_time(struct domain *d)
     spin_unlock(&wc_lock);
 }
 
+int cpu_frequency_change(u64 freq)
+{
+    struct cpu_time *t = &this_cpu(cpu_time);
+    u64 curr_tsc;
+
+    local_irq_disable();
+    set_time_scale(&t->tsc_scale, freq);
+    rdtscll(curr_tsc);
+    t->local_tsc_stamp = curr_tsc;
+    t->stime_local_stamp = get_s_time();
+    t->stime_master_stamp = read_platform_stime();
+    local_irq_enable();
+
+    /* A full epoch should pass before we check for deviation. */
+    set_timer(&t->calibration_timer, NOW() + EPOCH);
+    if ( smp_processor_id() == 0 )
+        platform_time_calibration();
+
+    return 0;
+}
+
 /* Set clock to <secs,usecs> after 00:00:00 UTC, 1 January, 1970. */
 void do_settime(unsigned long secs, unsigned long nsecs, u64 system_time_base)
 {
@@ -866,12 +887,14 @@ static void local_time_calibration(void *unused)
            error_factor, calibration_mul_frac, tsc_shift);
 #endif
 
-    /* Record new timestamp information. */
+    /* Record new timestamp information, atomically w.r.t. interrupts. */
+    local_irq_disable();
     t->tsc_scale.mul_frac = calibration_mul_frac;
     t->tsc_scale.shift    = tsc_shift;
     t->local_tsc_stamp    = curr_tsc;
     t->stime_local_stamp  = curr_local_stime;
     t->stime_master_stamp = curr_master_stime;
+    local_irq_enable();
 
     update_vcpu_system_time(current);
 
index fea688bf11b080208dc3b842fcf3f700e1cd8ac9..16cb989b857d92f3aab968f12d6aa80346dd4b08 100644 (file)
@@ -1728,10 +1728,16 @@ static int emulate_privileged_op(struct cpu_user_regs *regs)
             v->arch.guest_context.gs_base_user = res;
             break;
 #endif
+        case MSR_K8_FIDVID_STATUS:
+        case MSR_K8_FIDVID_CTL:
+            if ( (cpufreq_controller != FREQCTL_dom0_kernel) ||
+                 (boot_cpu_data.x86_vendor != X86_VENDOR_AMD) ||
+                 wrmsr_safe(regs->ecx, eax, edx) )
+                goto fail;
+            break;
         default:
             if ( wrmsr_hypervisor_regs(regs->ecx, eax, edx) )
                 break;
-
             if ( (rdmsr_safe(regs->ecx, l, h) != 0) ||
                  (eax != l) || (edx != h) )
                 gdprintk(XENLOG_WARNING, "Domain attempted WRMSR %p from "
@@ -1764,6 +1770,13 @@ static int emulate_privileged_op(struct cpu_user_regs *regs)
             regs->edx = v->arch.guest_context.gs_base_user >> 32;
             break;
 #endif
+        case MSR_K8_FIDVID_CTL:
+        case MSR_K8_FIDVID_STATUS:
+            if ( (cpufreq_controller != FREQCTL_dom0_kernel) ||
+                 (boot_cpu_data.x86_vendor != X86_VENDOR_AMD) ||
+                 rdmsr_safe(regs->ecx, regs->eax, regs->edx) )
+                goto fail;
+            break;
         case MSR_EFER:
             if ( rdmsr_safe(regs->ecx, regs->eax, regs->edx) )
                 goto fail;
index 50aacafb619bca48d517badf6a2b8d120b40d97f..9c040477dc05b1062ab7f5e07c5b9bc5a02fa9c4 100644 (file)
@@ -42,6 +42,17 @@ string_param("sched", opt_sched);
 static unsigned int opt_dom0_vcpus_pin;
 boolean_param("dom0_vcpus_pin", opt_dom0_vcpus_pin);
 
+enum cpufreq_controller cpufreq_controller;
+static void __init setup_cpufreq_option(char *str)
+{
+    if ( !strcmp(str, "dom0-kernel") )
+    {
+        cpufreq_controller = FREQCTL_dom0_kernel;
+        opt_dom0_vcpus_pin = 1;
+    }
+}
+custom_param("cpufreq", setup_cpufreq_option);
+
 #define TIME_SLOP      (s32)MICROSECS(50)     /* allow time to slip a bit */
 
 /* Various timer handlers. */
index 1e24537566668837dcbc9a235b8c50697a7680f9..069b29e6899543176a29fb3ec24da01ec2daac7a 100644 (file)
@@ -360,6 +360,9 @@ static inline void write_efer(__u64 val)
 #define MSR_K8_VM_CR                   0xC0010114
 #define MSR_K8_VM_HSAVE_PA             0xC0010117
 
+#define MSR_K8_FIDVID_CTL              0xC0010041
+#define MSR_K8_FIDVID_STATUS           0xC0010042
+
 /* MSR_K8_VM_CR bits: */
 #define _K8_VMCR_SVME_DISABLE          4
 #define K8_VMCR_SVME_DISABLE           (1 << _K8_VMCR_SVME_DISABLE)
index 773c3127700b77de82de528f6c3598ec3eac21c5..23cbbf2b793d77575284099fec2dea895aaeb108 100644 (file)
@@ -29,4 +29,6 @@ void init_percpu_time(void);
 struct ioreq;
 int dom0_pit_access(struct ioreq *ioreq);
 
+int cpu_frequency_change(u64 freq);
+
 #endif /* __X86_TIME_H__ */
index d1a44835de0813a05f36b8f09b6ebeeace7a08e7..ad7847a9d99b64a325475795c0743b8a51132d5e 100644 (file)
@@ -164,6 +164,16 @@ struct xenpf_enter_acpi_sleep {
 typedef struct xenpf_enter_acpi_sleep xenpf_enter_acpi_sleep_t;
 DEFINE_XEN_GUEST_HANDLE(xenpf_enter_acpi_sleep_t);
 
+#define XENPF_change_freq       52
+struct xenpf_change_freq {
+    /* IN variables */
+    uint32_t flags; /* Must be zero. */
+    uint32_t cpu;   /* Physical cpu. */
+    uint64_t freq;  /* New frequency (Hz). */
+};
+typedef struct xenpf_change_freq xenpf_change_freq_t;
+DEFINE_XEN_GUEST_HANDLE(xenpf_change_freq_t);
+
 struct xen_platform_op {
     uint32_t cmd;
     uint32_t interface_version; /* XENPF_INTERFACE_VERSION */
@@ -176,6 +186,7 @@ struct xen_platform_op {
         struct xenpf_platform_quirk    platform_quirk;
         struct xenpf_firmware_info     firmware_info;
         struct xenpf_enter_acpi_sleep  enter_acpi_sleep;
+        struct xenpf_change_freq       change_freq;
         uint8_t                        pad[128];
     } u;
 };
index f863f4a837e4b0d8382ae17d07f7bc691e8a032c..cf5342ccf112e9550e5a3af763364c59cee7b373 100644 (file)
@@ -499,6 +499,10 @@ static inline void vcpu_unblock(struct vcpu *v)
 #define is_hvm_domain(d) ((d)->is_hvm)
 #define is_hvm_vcpu(v)   (is_hvm_domain(v->domain))
 
+extern enum cpufreq_controller {
+    FREQCTL_none, FREQCTL_dom0_kernel
+} cpufreq_controller;
+
 #endif /* __SCHED_H__ */
 
 /*
index 0c7c80ebde845a4f69ce80cf615e657515890cfb..e70ad5350e2b1506439d2514b20da7210e9f7dac 100644 (file)
@@ -1,28 +1,10 @@
-/****************************************************************************
- * (C) 2002 - Rolf Neugebauer - Intel Research Cambridge
- ****************************************************************************
- *
- *        File: time.h
- *      Author: Rolf Neugebauer (neugebar@dcs.gla.ac.uk)
- *     Changes: 
- *              
- *        Date: Nov 2002
+/******************************************************************************
+ * time.h
  * 
- * Environment: Xen Hypervisor
- * Description: This file provides a one stop shop for all time related
- *              issues within the hypervisor. 
- * 
- *              The Hypervisor provides the following notions of time:
- *              Cycle Counter Time, System Time, Wall Clock Time, and 
- *              Domain Virtual Time.
- *
- ****************************************************************************
- * $Id: h-insert.h,v 1.4 2002/11/08 16:03:55 rn Exp $
- ****************************************************************************
+ * Copyright (c) 2002-2003 Rolf Neugebauer
+ * Copyright (c) 2002-2005 K A Fraser
  */
 
-
-
 #ifndef __XEN_TIME_H__
 #define __XEN_TIME_H__